﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Office.PowerPoint.STAMP.Common;

namespace Microsoft.Office.PowerPoint.STAMP.Controls
{
    /// <summary>
    /// A toolbar to display font formatting options.
    /// </summary>
    public partial class FormattingToolbar : UserControl
    {
        private FormattingToolbarSelection currentFontSelection;
        private bool suppressChangeEvents;

        /// <summary>
        /// Gets or sets the current font selection.
        /// </summary>
        /// <param name="value">
        ///   The current font selection.
        /// </param>
        public void UpdateCurrentFontSelection(FormattingToolbarSelection value)
        {
            currentFontSelection = value;
            suppressChangeEvents = true;
            UpdateControlValues();
            suppressChangeEvents = false;
        }

        /// <summary>
        /// Occurs when the Current Font Selection is changed.
        /// </summary>
        public event EventHandler<FormattingToolbarFontSelectionChangedEventArgs> FontSelectionChanged;

        private void OnFontSelectionChanged()
        {
            if (FontSelectionChanged != null)
            {
                FontSelectionChanged(this, new FormattingToolbarFontSelectionChangedEventArgs(currentFontSelection));
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FormattingToolbar"/> class.
        /// </summary>
        public FormattingToolbar()
        {
            suppressChangeEvents = true;
            InitializeComponent();
            InitialiseCurrentFontSelection();
            InitialiseDropDowns();
            UpdateControlValues();
            suppressChangeEvents = false;
        }

        private void InitialiseCurrentFontSelection()
        {
            currentFontSelection = FormattingToolbarSelection.Default;
        }

        private void InitialiseDropDowns()
        {
            FontDropDownItem[] fontDropDownItems = FontService.AvailableFonts.Select(familyItem => new FontDropDownItem(familyItem)).ToArray();
            fontNameDropdown.Items.AddRange(fontDropDownItems);
            
            string[] availableFontSizes = new[] { CaptionFontSize.Auto.Text, "8", "9", "10", "11", "12", "14", "16", "18","20","22","24","26","28","36","48","72" };
            fontSizeDropdown.Items.AddRange(availableFontSizes);
        }

        private void UpdateControlValues()
        {
            UpdateFontNameDropdown();
            UpdateFontSizeDropdown();

            boldButton.Checked = currentFontSelection.IsBold ?? false;
            italicButton.Checked = currentFontSelection.IsItalic ?? false;
            underlineButton.Checked = currentFontSelection.IsUnderline ?? false;

            ToggleAlignmentButtons(currentFontSelection.Alignment);

            fontColorButton.ForeColor = currentFontSelection.FontColor ?? Color.Transparent;
            backgroundColorSelector.ForeColor = currentFontSelection.BackgroundColor ?? Color.Transparent;
        }

        private void UpdateFontSizeDropdown()
        {
            if (currentFontSelection.FontSize.IsAuto)
                fontSizeDropdown.SelectedIndex = fontSizeDropdown.Items.IndexOf(CaptionFontSize.Auto.Text);
            else if (currentFontSelection.FontSize.IsEmpty)
                fontSizeDropdown.Text = CaptionFontSize.Empty.Text;

            else
                fontSizeDropdown.Text = currentFontSelection.FontSize.Text;
        }

        private void UpdateFontNameDropdown()
        {
            IEnumerable<FontDropDownItem> fontDropDownItems = fontNameDropdown.Items.Cast<FontDropDownItem>();
            FontDropDownItem firstItem = fontDropDownItems.ElementAtOrDefault(0);
            if (currentFontSelection.FontFamily != null)
            {
                if (firstItem != null && firstItem == FontDropDownItem.Empty)
                    fontNameDropdown.Items.Remove(firstItem);
                fontNameDropdown.SelectedItem = fontDropDownItems.FirstOrDefault(fontItem => fontItem.Name.Equals(currentFontSelection.FontFamily.Name)) ?? GetDefaultFontDropDownItem();
            }
            else
            {
                if (firstItem != null && firstItem != FontDropDownItem.Empty && FontDropDownItem.Empty != null)
                    fontNameDropdown.Items.Insert(0, FontDropDownItem.Empty);
                fontNameDropdown.SelectedItem = FontDropDownItem.Empty;
            }
        }

        private FontDropDownItem GetDefaultFontDropDownItem()
        {
            return fontNameDropdown.Items.Cast<FontDropDownItem>().First(
                fontItem => fontItem.Name.Equals(FontService.DefaultFont.Name));
        }

        private void ToggleAlignmentButtons(HorizontalAlignment? alignment)
        {
            leftAlignButton.Checked = alignment == HorizontalAlignment.Left;
            centerAlignButton.Checked = alignment == HorizontalAlignment.Center;
            rightAlignButton.Checked = alignment == HorizontalAlignment.Right;
        }

        private void fontNameDropdown_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (suppressChangeEvents)
                return;
            FontDropDownItem selectedFontItem = (FontDropDownItem) fontNameDropdown.SelectedItem;
            FontFamily font = selectedFontItem.IsEmpty ? null : selectedFontItem.Family;
            currentFontSelection = new FormattingToolbarSelection(font, currentFontSelection.FontSize,
                                                                   currentFontSelection.Alignment,
                                                                   currentFontSelection.IsItalic,
                                                                   currentFontSelection.IsBold,
                                                                   currentFontSelection.IsUnderline,
                                                                   currentFontSelection.FontColor,
                                                                   currentFontSelection.BackgroundColor);
            OnFontSelectionChanged();
        }

        private void fontSizeDropdown_TextChanged(object sender, EventArgs e)
        {
            if (suppressChangeEvents)
                return;
            CaptionFontSize oldSize = currentFontSelection.FontSize;
            CaptionFontSize newFontSize = GetFontSize();
            if (oldSize != newFontSize)
            {
                currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily, newFontSize,
                                                                       currentFontSelection.Alignment,
                                                                       currentFontSelection.IsItalic,
                                                                       currentFontSelection.IsBold,
                                                                       currentFontSelection.IsUnderline,
                                                                   currentFontSelection.FontColor,
                                                                   currentFontSelection.BackgroundColor);

                OnFontSelectionChanged();
            }
        }

        private CaptionFontSize GetFontSize()
        {
            float updatedSize;
            if (fontSizeDropdown.Text == CaptionFontSize.Auto.Text)
            {
                return CaptionFontSize.Auto;
            }
            if (fontSizeDropdown.Text == CaptionFontSize.Empty.Text)
            {
                return CaptionFontSize.Empty;
            }
            if (float.TryParse(fontSizeDropdown.Text, out updatedSize))
            {
                return new CaptionFontSize(updatedSize);
            }
            fontSizeDropdown.Text = currentFontSelection.FontSize.ToString();
            return currentFontSelection.FontSize;
        }

        private void boldButton_Click(object sender, EventArgs e)
        {
            if (suppressChangeEvents)
                return;
            currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily,
                                                                   currentFontSelection.FontSize,
                                                                   currentFontSelection.Alignment,
                                                                   currentFontSelection.IsItalic, 
                                                                   boldButton.Checked,
                                                                   currentFontSelection.IsUnderline,
                                                                   currentFontSelection.FontColor,
                                                                   currentFontSelection.BackgroundColor);
            OnFontSelectionChanged();
        }

        private void italicButton_Click(object sender, EventArgs e)
        {
            if (suppressChangeEvents)
                return;
            currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily,
                                                                   currentFontSelection.FontSize,
                                                                   currentFontSelection.Alignment,
                                                                   italicButton.Checked, 
                                                                   currentFontSelection.IsBold,
                                                                   currentFontSelection.IsUnderline,
                                                                   currentFontSelection.FontColor,
                                                                   currentFontSelection.BackgroundColor);

            OnFontSelectionChanged();
        }

        private void underlineButton_Click(object sender, EventArgs e)
        {
            if (suppressChangeEvents)
                return;
            currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily,
                                                                   currentFontSelection.FontSize,
                                                                   currentFontSelection.Alignment,
                                                                   currentFontSelection.IsItalic,
                                                                   currentFontSelection.IsBold,
                                                                   underlineButton.Checked,
                                                                   currentFontSelection.FontColor,
                                                                   currentFontSelection.BackgroundColor);
            OnFontSelectionChanged();
        }

        private void leftAlignButton_Click(object sender, EventArgs e)
        {
            if (currentFontSelection.Alignment == HorizontalAlignment.Left)
            {
                leftAlignButton.Checked = true;
                return;
            }
            HandleAlignmentButtonClicked(HorizontalAlignment.Left);
        }

        private void centerAlignButton_Click(object sender, EventArgs e)
        {
            if (currentFontSelection.Alignment == HorizontalAlignment.Center)
            {
                centerAlignButton.Checked = true;
                return;
            }
            HandleAlignmentButtonClicked(HorizontalAlignment.Center);
        }

        private void rightAlignButton_Click(object sender, EventArgs e)
        {
            if (currentFontSelection.Alignment == HorizontalAlignment.Right)
            {
                rightAlignButton.Checked = true;
                return;
            }
            HandleAlignmentButtonClicked(HorizontalAlignment.Right);
        }

        private void HandleAlignmentButtonClicked(HorizontalAlignment alignment)
        {
            if (suppressChangeEvents)
                return;
            currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily,
                                                                   currentFontSelection.FontSize, alignment,
                                                                   currentFontSelection.IsItalic,
                                                                   currentFontSelection.IsBold, 
                                                                   currentFontSelection.IsUnderline,
                                                                   currentFontSelection.FontColor,
                                                                   currentFontSelection.BackgroundColor);
            suppressChangeEvents = true;
            ToggleAlignmentButtons(alignment);
            suppressChangeEvents = false;
            OnFontSelectionChanged();
        }

        private void fontColorButton_Changed(object sender, ColorButtonColorChangedEventArgs e)
        {
            if (!suppressChangeEvents && currentFontSelection.FontColor != e.SelectedColor)
            {
                currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily,
                                                                   currentFontSelection.FontSize,
                                                                   currentFontSelection.Alignment,
                                                                   currentFontSelection.IsItalic,
                                                                   currentFontSelection.IsBold,
                                                                   currentFontSelection.IsUnderline,
                                                                   e.SelectedColor,
                                                                   currentFontSelection.BackgroundColor);
                OnFontSelectionChanged();
            }
        }

        private void backgroundColorSelector_Changed(object sender, ColorButtonColorChangedEventArgs e)
        {
            if (!suppressChangeEvents && currentFontSelection.BackgroundColor != e.SelectedColor)
            {
                currentFontSelection = new FormattingToolbarSelection(currentFontSelection.FontFamily,
                                                                   currentFontSelection.FontSize,
                                                                   currentFontSelection.Alignment,
                                                                   currentFontSelection.IsItalic,
                                                                   currentFontSelection.IsBold,
                                                                   currentFontSelection.IsUnderline,
                                                                   currentFontSelection.FontColor,
                                                                   e.SelectedColor);
                OnFontSelectionChanged();
            }
        }
    }

    /// <summary>
    /// EventArgs for use when the font attributes are changed on the <see cref="FormattingToolbar"/>
    /// </summary>
    public class FormattingToolbarFontSelectionChangedEventArgs : EventArgs
    {
        private readonly FormattingToolbarSelection formattingToolbarSelection;

        /// <summary>
        /// Initializes a new instance of the <see cref="FormattingToolbarFontSelectionChangedEventArgs"/> class.
        /// </summary>
        /// <param name="formattingToolbarSelection">The formatting toolbar selection.</param>
        public FormattingToolbarFontSelectionChangedEventArgs(FormattingToolbarSelection formattingToolbarSelection)
        {
            this.formattingToolbarSelection = formattingToolbarSelection;
        }

        /// <summary>
        /// Gets the updated formatting toolbar selection.
        /// </summary>
        public FormattingToolbarSelection UpdatedFormattingToolbarSelection
        {
            get { return formattingToolbarSelection; }
        }
    }
}
